-
-
Notifications
You must be signed in to change notification settings - Fork 17
DEX-1270 remove id from optionEditor #412
DEX-1270 remove id from optionEditor #412
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me.
@@ -42,7 +41,7 @@ export default function OptionEditor({ | |||
flexDirection: 'column', | |||
marginBottom: 12, | |||
}} | |||
key={option.id} | |||
key={option.value} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Option values and/or labels cannot be guaranteed to be unique within this component. If a user clicks "Add Another Option" several times, each option looks exactly the same: [{ label: '', value: '' }, { label: '', value: '' }, // etc.]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, "value" is not a stable identifier for a key because whenever an option's value is updated, the key changes. This causes the value input to lose focus.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm...what would you recommend in this case? Just generate a uuid?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Option values and/or labels cannot be guaranteed to be unique within this component. If a user clicks "Add Another Option" several times, each option looks exactly the same: [{ label: '', value: '' }, { label: '', value: '' }, // etc.]
I think that this will at least be partially ameliorated by Jon's back end work on DEX-1270 (this makes me realize that I mis-typed and this whole FE PR is for ticket DEX-1120).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will be partially ameliorated because we will be able to know that the values from the database are unique. However, while values are being added and edited within the dialog, it will always be possible for multiple value fields to be the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
once the values from the database are unique, it might be sufficient to add a timestamp property to objects created on the frontend ie. { label, value, created: Date.now() }
. obviously the backend objects wouldn't have these but you could use key={o?.created || o?.value}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, "value" is not a stable identifier for a key because whenever an option's value is updated, the key changes. This causes the value input to lose focus.
for this to be resolved we would need to make sure the value used in the keys was the backend value, not the frontend's input value that changes as typed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok... with the most recent changes, I believe that the only way that two options would have the same key would be if 1) they were migrated and 2) they had the same exact value.
I would argue that the behavior of deletion of any one of these resulting in the deletion of all of them is a feature rather than a bug, because it helps improve the usability of the product.
aaf2d88
to
47e8dcb
Compare
47e8dcb
to
77c5ee3
Compare
src/components/Button.jsx
Outdated
> | ||
{children} | ||
</Button> | ||
<Tooltip title={tooltiptext}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this makes things more complicated, but the Tooltip component shouldn't be rendered unless it is being used
option => !option?.value || !option?.label, | ||
).length > 0 | ||
} | ||
tooltiptext={ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be camelCase (tooltipText)
319b5df
to
2ffec49
Compare
The code has been changed since the review.
src/components/Button.jsx
Outdated
display = 'panel', | ||
loading = false, | ||
style, | ||
disabled, | ||
showTooltip = false, | ||
tooltipText = '', | ||
size, | ||
...rest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anything that is being passed through can just be part of ...rest
. I think you only need:
{
showTooltip = false,
tooltipText = '',
...rest
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing everything else actually broke things. Curious.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't see any errors with this:
const ButtonWithTooltip = function (
{
showTooltip = false,
tooltipText = '',
...rest
},
ref,
) {
if (showTooltip)
return (
<Tooltip title={tooltipText}>
<span>
<CoreForwardRef ref={ref} {...rest} />
</span>
</Tooltip>
);
else
return (
<CoreForwardRef ref={ref} {...rest} />
);
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤦 Thank you. Addressed in 75e6ad4
showTooltip | ||
tooltipText={ | ||
displayedOptions.filter( | ||
option => !option?.value || !option?.label, | ||
).length > 0 | ||
? intl.formatMessage({ | ||
id: 'UNFINISHED_OPTIONS', | ||
}) | ||
: '' | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the options are valid, there is no need for a Tool tip.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what you're thinking here. Do you mean that it would be better to have a separate element when options are valid?
I can't pass null to a tooltip without weird behavior (it just shows an empty tooltip), but I can pass undefined. Is this what you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed in b2c0f77
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that showTooltip
should be false
. It that case tooltipText will not be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah. Thanks. Addressed in ed875d1
displayedOptions.filter( | ||
option => !option?.value || !option?.label, | ||
).length > 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be worth defining an areOptionsValid
variable for clarity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed in b2c0f77
5767ec6
to
b2c0f77
Compare
filter( | ||
displayedOptions, | ||
option => !option?.value || !option?.label, | ||
).length === 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some
might be easier to read here.
https://lodash.com/docs/#some
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix in 0f31a48
option => !option?.value || !option?.label, | ||
).length === 0; | ||
const areAllValuesUnique = | ||
uniq(map(displayedOptions, option => option?.value)).length === |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uniqBy
would let you skip the map
https://lodash.com/docs/#uniqBy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix in 0f31a48
flexDirection: 'column', | ||
marginBottom: 12, | ||
}} | ||
key={optionIndex} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the index as the key feels dangerous. I agree that it works in this case though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was getting too complicated, and this really helped to simplify.
})} | ||
); | ||
}, | ||
[], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The signature for map
does not have a third argument.
https://lodash.com/docs/#map
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WHY DO I KEEP DOING THIS?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix in 0f31a48
Pull request checklist:
Features and bugfixes should be PRed into the
develop
branch, notmain
All text is internationalized
There are no linter errors
New features support all states (loading, error, etc)
Thanks for keeping it clean! Feel free to merge your own pull request after it has been approved - just use the "squash & merge" option.
This PR removes the unneccesary id attribute from custom filed options. This brings newly-created custom field options in line with the current behavior of migrated custom fields.
The removal of id here does not seem to affect the metadata cards for sightings or encounters.
It was decided that, because the end users will be exporting, bulk importing, and otherwise using these custom field options, they should be in control of what both the labels and values are (provided that these are unique - see DEX-1270 for that issue).
QA notes:
Old behavior when an admin tried to remove any multi-select custom field option:
Before deleting "Standing":
After deleting "Standing":
(i.e., they would all be removed)
New behavior after this PR gets merged:
Before deleting "Standing":
After deleting "Standing":
Other things to confirm: